package com.treasure.web.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.treasure.common.enums.LoginRouteEnum;
import com.treasure.common.enums.LoginTypeEnum;
import com.treasure.common.enums.RegisterChannelEnum;
import com.treasure.common.exception.ParameterException;
import com.treasure.common.exception.ServiceException;
import com.treasure.common.model.PageResult;
import com.treasure.common.model.SessionUser;
import com.treasure.common.model.SessionUserHolder;
import com.treasure.common.types.Corp;
import com.treasure.common.types.CorpInvitationCode;
import com.treasure.common.types.PhoneNumber;
import com.treasure.common.types.VerifyCode;
import com.treasure.common.utils.MD5Utils;
import com.treasure.common.utils.RandomIdGenerator;
import com.treasure.domain.domain.TextVariablesCombinedDomainService;
import com.treasure.infrastructure.domain.impl.client.EmailSenderClient;
import com.treasure.infrastructure.model.po.*;
import com.treasure.infrastructure.repository.dao.mapper.*;
import com.treasure.domain.domain.entity.document.CreateAccountNotify;
import com.treasure.web.command.PageConvertor;
import com.treasure.web.command.PasswordEditRequest;
import com.treasure.web.command.base.PageBaseQuery;
import com.treasure.web.command.request.CorpEditRequest;
import com.treasure.web.command.request.CreateCorpAccountRequest;
import com.treasure.web.command.request.EditUserPasswordRequest;
import com.treasure.web.command.request.login.ExternalLoginRequest;
import com.treasure.web.command.response.CorpAccountTokenResponse;
import com.treasure.web.command.response.CorpUserInfoResponse;
import com.treasure.web.configure.CallBackMailConfig;
import com.treasure.web.mapstruct.AccountCopyBuilder;
import com.treasure.web.command.request.login.LoginRequest;
import com.treasure.web.command.request.login.RegisterRequest;
import com.treasure.web.command.response.AccountUserInfoResponse;
import com.treasure.web.mapstruct.CorpUserInfoAssembler;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.treasure.web.service.*;
import com.treasure.common.threadpool.GlobalThreadPoolEnum;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author sunhongmin
 * @since 2023-08-31
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> implements IAccountService {

    public static final String SLOT_AITREASURECHEST_KEY = "aitreasurechest";
    private final SmsService smsService;
    private final ICorpAccessTokenService corpAccessTokenService;
    private final ICorpUserInfoService corpUserInfoService;
    private final ICorpInfoService corpInfoService;
    private final ICorpRoleInfoService corpRoleInfoService;
    private final IUserRoleMappingService userRoleMappingService;
    private final ICorpDepartmentInfoService corpDepartmentInfoService;
    private final IKnowledgeBaseService knowledgeBaseService;
    private final IAiRobotService aiRobotService;
    private final CallBackMailConfig callBackMailConfig;
    private final EmailSenderClient emailSenderClient;
    private final TextVariablesCombinedDomainService textVariablesCombinedDomainService;

    private final ExecutorService threadPool = GlobalThreadPoolEnum.GLOBAL_BACKTASK_THREAD_POOL.getExecutorService();

    @Override
    @Transactional(rollbackFor = {Exception.class})
    public void register(RegisterRequest request) {
        request.validate();

        CorpInfo corpInfo = getAndVerifyCorpInfo(new CorpInvitationCode(request.getInvitationCode()));
        LocalDateTime now = LocalDateTime.now();

        if (Objects.equals(request.getLoginType(), LoginTypeEnum.VERIFY_CODE.getCode())) {
            // 验证码校验
            codeVerified(request.getPhoneNumber(), request.getPassword());
        }

        QueryWrapper<Account> accountQuery = new QueryWrapper<>();
        accountQuery.eq("phone_number", request.getPhoneNumber());
        Account account = this.getOne(accountQuery);

        // 第一种情况，账户及企业用户记录都不存在，则创建入库
        boolean isFirstCreate = Objects.isNull(account);
        Account createAccount;
        if (isFirstCreate) {
            // 创建新账户
            createAccount = getCreateAccount(RandomIdGenerator.userId(corpInfo.getCorpId()), request.getPhoneNumber(), request.getPassword(), now);
            this.save(createAccount);
            // 插入corpUserInfo 记录
            insertCorpUserInfo(corpInfo, createAccount, now, RegisterChannelEnum.SYSTEM_REGIS, false);
            return;
        }

        // 第二种情况，账户存在，企业用户记录不存在，则插入企业用户记录
        QueryWrapper<CorpUserInfo> userInfoQuery = new QueryWrapper<>();
        userInfoQuery.lambda()
                .eq(CorpUserInfo::getUserId, account.getUserId())
                .eq(CorpUserInfo::getCorpId, corpInfo.getCorpId());
        CorpUserInfo existsCorpUserInfo = corpUserInfoService.getOne(userInfoQuery);
        if (Objects.isNull(existsCorpUserInfo)) {
            insertCorpUserInfo(corpInfo, account, now, RegisterChannelEnum.SYSTEM_REGIS, false);
            return;
        }

        //
        throw new ServiceException("该手机号已在该企业/高校注册过账户，请直接登录");
    }

    @Override
    @Transactional(rollbackFor = {Exception.class})
    public List<CorpUserInfo> login(LoginRequest loginRequest, LoginRouteEnum loginRouteEnum) {
        loginRequest.validate(loginRouteEnum);
        // 普通用户需要验证企业认证码
        CorpInfo corpInfo = null;
        if (Objects.equals(loginRouteEnum, LoginRouteEnum.NORMAL_LOGIN_ROUTE)) {
            corpInfo = getAndVerifyCorpInfo(new CorpInvitationCode(loginRequest.getInvitationCode()));
        }
        LocalDateTime now = LocalDateTime.now();

        Account account;
        if (Objects.equals(loginRequest.getLoginType(), LoginTypeEnum.VERIFY_CODE.getCode())) {
            // 验证码登录，未使用的手机号将自动创建新账户 & 管理员账户不存在报错
            account = loginVerifyByVerifyCode(loginRequest, corpInfo, now, loginRouteEnum);
        } else {
            // 密码登录
            account = loginVerifyByPassword(loginRequest.getPhoneNumber(), loginRequest.getPassword());
        }

        // 获取企业用户信息
        List<CorpUserInfo> corpUserInfos = getCorpUserInfoList(account.getUserId(), loginRouteEnum);
        if (CollectionUtils.isEmpty(corpUserInfos)) {
            throw new ServiceException("未获取到企业/高校用户信息，请尝试重新注册后，重新进行登录");
        }

        threadPool.submit(() -> {
            // 更新用户最后登录时间
            Account updateAccount = AccountCopyBuilder.INSTANCE.copyAccount(account);
            updateAccount.setLastLogin(now);
            this.updateById(account);
        });
        return corpUserInfos;
    }

    @Override
    @Transactional(rollbackFor = {Exception.class})
    public CorpUserInfo externalLogin(ExternalLoginRequest externalLoginRequest) {
        CorpInfo corpInfo = getCorpInfoFromInviteCode(externalLoginRequest.getInvitationCode());
        if (Objects.isNull(corpInfo)) {
            throw new ParameterException("未获取到企业/高校信息，企业/高校认证码有误");
        }
        CorpAccountTokenResponse corpAccountTokenInfo = corpAccessTokenService.getCorpAccountTokenInfo(new Corp(corpInfo.getCorpId()));
        if (!corpAccountTokenInfo.hasEffectiveCorp()) {
            throw new ServiceException("企业/高校授权未认证或已过期");
        }
        if (!corpAccountTokenInfo.checkAuth(externalLoginRequest.getAuthToken())) {
            throw new ServiceException("跳转登录失败，认证信息未通过");
        }

        String loginUserId = externalLoginRequest.getUserId();
        if (StringUtils.isBlank(externalLoginRequest.getUserId())) {
            loginUserId = RandomIdGenerator.userId(corpInfo.getCorpId());
        }

        // 尝试获取用户信息
        QueryWrapper<CorpUserInfo> corpUserQuery = new QueryWrapper<>();
        corpUserQuery.lambda().eq(CorpUserInfo::getCorpId, corpInfo.getCorpId())
                .eq(CorpUserInfo::getUserId, loginUserId);
        CorpUserInfo corpUserInfo = corpUserInfoService.getOne(corpUserQuery);
        if (Objects.nonNull(corpUserInfo)) {
            return corpUserInfo;
        }

        // 创建账户
        Account account = this.createAccountAndCorpUserInfo(loginUserId, loginUserId, corpInfo, LocalDateTime.now(), RegisterChannelEnum.ACCESS_REGISTER, false, null);
        QueryWrapper<CorpUserInfo> createCorpUserQuery = new QueryWrapper<>();
        createCorpUserQuery.lambda().eq(CorpUserInfo::getCorpId, corpInfo.getCorpId())
                .eq(CorpUserInfo::getUserId, account.getUserId());
        CorpUserInfo createCorpUserInfo = corpUserInfoService.getOne(createCorpUserQuery);
        if (Objects.nonNull(createCorpUserInfo)) {
            return createCorpUserInfo;
        }

        throw new ServiceException("创建账户失败");
    }

    @Override
    public CorpInfo createCorpAccount(CreateCorpAccountRequest createCorpAccountRequest, RegisterChannelEnum registerChannel) throws IOException, IllegalAccessException {
        Objects.requireNonNull(registerChannel, "注册通道参数缺失");
//        if (Objects.equals(RegisterChannelEnum.ACCESS_REGISTER, registerChannel)) {
//            // 验证码校验
//            this.codeVerified(createCorpAccountRequest.getManageEmail(), createCorpAccountRequest.getVerifyCode());
//        }
        // 企业名重复校验
        if (isCorpExists(createCorpAccountRequest)) {
            throw new ParameterException("已存在该企业/高校名称，name=" + createCorpAccountRequest.getCorpName());
        }
        LocalDateTime now = LocalDateTime.now();
        LocalDate nowDate = LocalDate.from(now);


        QueryWrapper<Account> accountQuery = new QueryWrapper<>();
        accountQuery.lambda().eq(Account::getPhoneNumber, createCorpAccountRequest.getManageEmail());
        Account existsAccount = getOne(accountQuery);
        if (Objects.nonNull(existsAccount)) {
            // 为了简化企业端后台登录流程，暂不支持同一个账号绑定多个企业的管理员身份
            throw new ParameterException("该账号已经关联了企业/高校，暂不支持同一个账号关联多个主体，请联系系统提供方进行支持");
        }

        // 创建企业信息
        CorpInfo createCorpInfo = getCreateCorpInfo(createCorpAccountRequest, registerChannel, now, nowDate);
        corpInfoService.save(createCorpInfo);

        // 创建管理员账户
        Account createAccount = createAccountAndCorpUserInfo(RandomIdGenerator.userId(createCorpInfo.getCorpId()), createCorpAccountRequest.getManageEmail(), createCorpInfo, now, registerChannel, true, createCorpAccountRequest.getPassword());

        // 创建角色
        CorpRoleInfo createRoleInfo = getCreateRoleInfo(now, createCorpInfo);
        corpRoleInfoService.save(createRoleInfo);

        // 角色用户关联
        UserRoleMapping userRoleMapping = getCreateUserRoleMapping(now, createCorpInfo, createAccount, createRoleInfo);
        userRoleMappingService.save(userRoleMapping);

        // 企业默认部门
        CorpDepartmentInfo corpDepartmentInfo = getCreateCorpDepartmentInfo(now, createCorpInfo, createAccount);
        corpDepartmentInfoService.save(corpDepartmentInfo);

        // 组织架构用户关联
        CorpUserInfo updateUserInfo = getUpdateUserInfo(createCorpInfo, createAccount, corpDepartmentInfo);
        corpUserInfoService.updateById(updateUserInfo);

        // 创建默认知识库
        KnowledgeBase knowledgeBase = getCreateKnowledgeBese(now, createCorpInfo, createAccount);
        knowledgeBaseService.save(knowledgeBase);

        // 创建企业默认机器人
        AiRobot aiRobot = getCreateAiRobot(now, createCorpInfo, createAccount, corpDepartmentInfo, knowledgeBase);
        aiRobotService.save(aiRobot);

        // 推送创建完成信息
        CreateAccountNotify createAccountNotify = getCreateAccountNotify(createCorpAccountRequest, registerChannel, now, createCorpInfo);
        String notifyMessage = textVariablesCombinedDomainService.createAccountTemplate(createAccountNotify);
        emailSenderClient.sendTextMailMessage(Collections.singletonList(callBackMailConfig.getCallBackAccount()), "系统创建账户通知", notifyMessage);
        return createCorpInfo;
    }

    @Override
    public void corpEdit(CorpEditRequest corpEditRequest) {
        QueryWrapper<CorpInfo> corpQuery = new QueryWrapper<>();
        corpQuery.lambda().eq(CorpInfo::getId, corpEditRequest.getId());
        CorpInfo corpInfo = corpInfoService.getOne(corpQuery);
        if (Objects.isNull(corpInfo)) {
            throw new ParameterException("企业信息获取失败");
        }

        CorpInfo updateCorp = new CorpInfo();
        updateCorp.setId(corpInfo.getId());
        updateCorp.setCorpName(corpEditRequest.getCorpName());
        updateCorp.setIndustry(corpEditRequest.getIndustry());
        updateCorp.setLogoUrl(corpEditRequest.getLogoUrl());
        updateCorp.setCustomSiteTitle(corpEditRequest.getCustomSiteTitle());
        updateCorp.setContactor(corpEditRequest.getContactor());
        updateCorp.setPurpose(corpEditRequest.getPurpose());
        updateCorp.setHasOpen(corpEditRequest.getHasOpen());
        updateCorp.setExpiryDate(LocalDate.parse(corpEditRequest.getExpiryDate(), DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        updateCorp.setUserLimit(corpEditRequest.getUserLimit());
        corpInfoService.updateById(updateCorp);
    }

    private boolean isCorpExists(CreateCorpAccountRequest createCorpAccountRequest) {
        QueryWrapper<CorpInfo> corpInfoQuery = new QueryWrapper<>();
        corpInfoQuery.lambda().eq(CorpInfo::getCorpName, createCorpAccountRequest.getCorpName());
        long existsCorp = corpInfoService.count(corpInfoQuery);
        return existsCorp > 0;
    }

    @NotNull
    private static CreateAccountNotify getCreateAccountNotify(CreateCorpAccountRequest createCorpAccountRequest, RegisterChannelEnum registerChannel, LocalDateTime now, CorpInfo createCorpInfo) {
        CreateAccountNotify createAccountNotify = new CreateAccountNotify();
        createAccountNotify.setCorpName(createCorpInfo.getCorpName());
        createAccountNotify.setIndustry(createCorpInfo.getIndustry());
        createAccountNotify.setExpiryDate(createCorpInfo.getExpiryDate());
        createAccountNotify.setUserLimit(createCorpInfo.getUserLimit());
        createAccountNotify.setManageEmail(createCorpAccountRequest.getManageEmail());
        createAccountNotify.setCreateSource(Objects.equals(registerChannel, RegisterChannelEnum.ACCESS_REGISTER) ? "试用开通" : "系统创建");
        createAccountNotify.setCreateUser(Objects.equals(registerChannel, RegisterChannelEnum.ACCESS_REGISTER) ? createCorpAccountRequest.getManageEmail() : SessionUserHolder.getSessionUser().getUserName());
        createAccountNotify.setCreateTime(now);
        return createAccountNotify;
    }

    @NotNull
    private CorpUserInfo getUpdateUserInfo(CorpInfo createCorpInfo, Account createAccount, CorpDepartmentInfo corpDepartmentInfo) {
        QueryWrapper<CorpUserInfo> corpUserQuery = new QueryWrapper<>();
        corpUserQuery.lambda().eq(CorpUserInfo::getCorpId, createCorpInfo.getCorpId())
                .eq(CorpUserInfo::getUserId, createAccount.getUserId());
        CorpUserInfo corpUserInfo = corpUserInfoService.getOne(corpUserQuery);
        CorpUserInfo updateUserInfo = new CorpUserInfo();
        updateUserInfo.setId(corpUserInfo.getId());
        updateUserInfo.setDefaultDepartment(corpDepartmentInfo.getId().intValue());
        updateUserInfo.setDepartments(corpDepartmentInfo.getId().toString());
        return updateUserInfo;
    }

    @NotNull
    private static AiRobot getCreateAiRobot(LocalDateTime now, CorpInfo createCorpInfo, Account createAccount, CorpDepartmentInfo corpDepartmentInfo, KnowledgeBase knowledgeBase) {
        AiRobot aiRobot = new AiRobot();
        aiRobot.setCorpId(createCorpInfo.getCorpId());
        aiRobot.setRobotName("默认机器人");
        aiRobot.setRobotAvatar("");
        aiRobot.setKnowledgeId(knowledgeBase.getId().intValue());
        aiRobot.setAvailableDepartments(corpDepartmentInfo.getId().toString());
        aiRobot.setHasSupplementEnabled(false);
        aiRobot.setSupplementMembers("");
        aiRobot.setCreateTime(now);
        aiRobot.setCreatorId(createAccount.getUserId());
        aiRobot.setEditTime(now);
        aiRobot.setEditorId(createAccount.getUserId());
        aiRobot.setHasDisabled(false);
        return aiRobot;
    }

    @NotNull
    private static KnowledgeBase getCreateKnowledgeBese(LocalDateTime now, CorpInfo createCorpInfo, Account createAccount) {
        KnowledgeBase knowledgeBase = new KnowledgeBase();
        knowledgeBase.setCorpId(createCorpInfo.getCorpId());
        knowledgeBase.setKnowledgeName("学校默认知识库");
        knowledgeBase.setKnowledgeDesc("学校默认知识库");
        knowledgeBase.setHasDeleted(false);
        knowledgeBase.setCreateTime(now);
        knowledgeBase.setCreatorId(createAccount.getUserId());
        return knowledgeBase;
    }

    @NotNull
    private static CorpDepartmentInfo getCreateCorpDepartmentInfo(LocalDateTime now, CorpInfo createCorpInfo, Account createAccount) {
        CorpDepartmentInfo corpDepartmentInfo = new CorpDepartmentInfo();
        corpDepartmentInfo.setCorpId(createCorpInfo.getCorpId());
        corpDepartmentInfo.setDepartmentName(createCorpInfo.getCorpName());
        corpDepartmentInfo.setDepartmentCode("001");
        corpDepartmentInfo.setDepartmentManager(createAccount.getUserId());
        corpDepartmentInfo.setParentId(0);
        corpDepartmentInfo.setHasDisabled(false);
        corpDepartmentInfo.setDepartmentPath("0");
        corpDepartmentInfo.setCreateTime(now);
        corpDepartmentInfo.setModifyTime(now);
        return corpDepartmentInfo;
    }

    @NotNull
    private static UserRoleMapping getCreateUserRoleMapping(LocalDateTime now, CorpInfo createCorpInfo, Account createAccount, CorpRoleInfo createRoleInfo) {
        UserRoleMapping userRoleMapping = new UserRoleMapping();
        userRoleMapping.setCorpId(createCorpInfo.getCorpId());
        userRoleMapping.setRoleId(createRoleInfo.getId().intValue());
        userRoleMapping.setUserId(createAccount.getUserId());
        userRoleMapping.setCreateTime(now);
        userRoleMapping.setModifyTime(now);
        return userRoleMapping;
    }

    @NotNull
    private static CorpRoleInfo getCreateRoleInfo(LocalDateTime now, CorpInfo createCorpInfo) {
        CorpRoleInfo createRoleInfo = new CorpRoleInfo();
        createRoleInfo.setCorpId(createCorpInfo.getCorpId());
        createRoleInfo.setRoleName("管理员角色");
        createRoleInfo.setHasDisabled(false);
        createRoleInfo.setCreateTime(now);
        return createRoleInfo;
    }

    @NotNull
    private static CorpInfo getCreateCorpInfo(CreateCorpAccountRequest createCorpAccountRequest, RegisterChannelEnum registerChannel, LocalDateTime now, LocalDate nowDate) {
        CorpInfo createCorpInfo = new CorpInfo();
        createCorpInfo.setCorpId(RandomIdGenerator.corpId());
        createCorpInfo.setCorpName(createCorpAccountRequest.getCorpName());
        createCorpInfo.setIndustry(createCorpAccountRequest.getIndustry());
        createCorpInfo.setCreateTime(now);
        createCorpInfo.setInviteCode(RandomIdGenerator.appKey());
        createCorpInfo.setHasOpen(false);
        createCorpInfo.setHasDeleted(false);
        createCorpInfo.setExpiryDate(nowDate.plusWeeks(2));
        createCorpInfo.setCompanyLevel("normal");
        createCorpInfo.setUserLimit(10);
        createCorpInfo.setRegisterChannel(registerChannel.getCode());
        createCorpInfo.setContactor(createCorpInfo.getContactor()); // 联系人
        createCorpInfo.setPurpose(createCorpInfo.getPurpose()); // 使用场景
        return createCorpInfo;
    }

    @Override
    public AccountUserInfoResponse getAccountUserInfo() {
        SessionUser sessionUser = SessionUserHolder.getAndCheckSessionUser();
        if (Objects.isNull(sessionUser)) {
            throw new ServiceException("获取当前登录用户信息失败，请重新登录后重试");
        }
        // 账户企业列表
        List<CorpUserInfo> corpUserInfos = getCorpUserInfoList(sessionUser.getUserId(), LoginRouteEnum.NORMAL_LOGIN_ROUTE);
        if (CollectionUtils.isEmpty(corpUserInfos)) {
            log.info("getCorpUserInfoList getCorpUserInfoList error corp_id:{},user_id:{}", sessionUser.getCorpId(), sessionUser.getUserId());
            throw new ServiceException("获取用户信息失败，请联系开发人员排查");
        }
        // 当前用户信息
        CorpUserInfo currentUser = corpUserInfos.stream().filter(it -> Objects.equals(it.getCorpId(), sessionUser.getCorpId()) && Objects.equals(it.getUserId(), sessionUser.getUserId())).findFirst().orElse(null);
        if (Objects.isNull(currentUser)) {
            log.info("getAccountUserInfo error corp_id:{},user_id:{}", sessionUser.getCorpId(), sessionUser.getUserId());
            throw new ServiceException("获取用户信息失败，请联系开发人员排查");
        }

        // 角色信息
        QueryWrapper<UserRoleMapping> userRoleMappingQuery = new QueryWrapper<>();
        userRoleMappingQuery.eq("corp_id", sessionUser.getCorpId())
                .eq("user_id", sessionUser.getUserId());
        List<UserRoleMapping> userRoleMappings = userRoleMappingService.list(userRoleMappingQuery);
        List<CorpRoleInfo> corpRoleInfoList = Collections.emptyList();
        if (CollectionUtils.isNotEmpty(userRoleMappings)) {
            List<Integer> userRoleIdList = userRoleMappings.stream().map(UserRoleMapping::getRoleId).collect(Collectors.toList());
            QueryWrapper<CorpRoleInfo> corpRoleInfoQuery = new QueryWrapper<>();
            corpRoleInfoQuery.lambda().eq(CorpRoleInfo::getCorpId, sessionUser.getCorpId())
                    .in(CorpRoleInfo::getId, userRoleIdList);
            corpRoleInfoList = corpRoleInfoService.list(corpRoleInfoQuery);
        }

        AccountUserInfoResponse accountUserInfoResponse = CorpUserInfoAssembler.INSTANCE.buildAccountUserInfo(currentUser);
        List<String> corpIdList = corpUserInfos.stream().map(CorpUserInfo::getCorpId).collect(Collectors.toList());

        QueryWrapper<CorpInfo> corpInfoQuery = new QueryWrapper<>();
        corpInfoQuery.lambda()
                .in(CorpInfo::getCorpId, corpIdList);
        List<CorpInfo> corpInfoList = corpInfoService.list(corpInfoQuery);

        List<AccountUserInfoResponse.UserCorpInfoResponse> userCorpInfoResponses = CorpUserInfoAssembler.INSTANCE.buildCorpInfo(corpInfoList);
        userCorpInfoResponses = userCorpInfoResponses.stream().peek(it -> {
            if (Objects.equals(it.getCorpId(), currentUser.getCorpId())) {
                it.setHasDefault(true);
            }
        }).collect(Collectors.toList());
        List<AccountUserInfoResponse.UserRoleInfoResponse> userRoleInfoResponses = CorpUserInfoAssembler.INSTANCE.buildRoleInfo(corpRoleInfoList);
        accountUserInfoResponse.setCorpInfoList(userCorpInfoResponses);
        accountUserInfoResponse.setUserRoleInfoList(userRoleInfoResponses);

        // 账户信息
        QueryWrapper<Account> accountQuery = new QueryWrapper<>();
        accountQuery.lambda()
                .eq(Account::getUserId, currentUser.getUserId());
        Account account = getOne(accountQuery);
        accountUserInfoResponse.setPhoneNumber(account.getPhoneNumber());

        return accountUserInfoResponse;
    }

    @Override
    public CorpInfo getCorpInfoFromInviteCode(String inviteCode) {
        QueryWrapper<CorpInfo> corpInfoQueryWrapper = new QueryWrapper<>();
        corpInfoQueryWrapper.lambda()
                .eq(CorpInfo::getInviteCode, inviteCode);
        CorpInfo corpInfo = corpInfoService.getOne(corpInfoQueryWrapper);
        if (Objects.nonNull(corpInfo) && corpInfo.getExpiryDate().isBefore(LocalDate.now())) {
            throw new ServiceException("企业已到期，corpId=" + corpInfo.getCorpId());
        }
        return corpInfo;
    }

    @Override
    public void editPassword(PasswordEditRequest passwordEditRequest) {
        Account account;
        if (Objects.equals(passwordEditRequest.getLoginType(), LoginTypeEnum.VERIFY_CODE)) {
            // 验证码校验
            account = codeVerified(passwordEditRequest.getPhoneNumber(), passwordEditRequest.getVerifyCode());
        } else {
            // 密码校验
            account = loginVerifyByPassword(passwordEditRequest.getPhoneNumber(), passwordEditRequest.getVerifyCode());
        }
        if (!Objects.equals(passwordEditRequest.getNewPassWord(), passwordEditRequest.getRePassword())) {
            throw new ParameterException("新密码与确认密码不一致");
        }
        Account editAccount = new Account();
        editAccount.setId(account.getId());
        editAccount.setPassword(MD5Utils.md5(SLOT_AITREASURECHEST_KEY + passwordEditRequest.getNewPassWord()));
        updateById(editAccount);
    }

    @Override
    public PageResult<CorpUserInfoResponse> userList(PageBaseQuery pageBaseQuery) {
        SessionUser sessionUser = SessionUserHolder.getAndCheckSessionUser();
        QueryWrapper<CorpUserInfo> userQuery = new QueryWrapper<>();
        userQuery.lambda().eq(CorpUserInfo::getCorpId, sessionUser.getCorpId());
        PageHelper.startPage(pageBaseQuery.getPage(), pageBaseQuery.getPageSize());
        List<CorpUserInfo> corpUserInfos = corpUserInfoService.list(userQuery);
        PageInfo<CorpUserInfo> pageInfo = new PageInfo<>(corpUserInfos);
        if (CollectionUtils.isEmpty(corpUserInfos)) {
            return PageConvertor.convertPage(pageInfo, Collections.emptyList());
        }

        Map<Long, String> departmentMap = getDepartmentMap(corpUserInfos);
        List<CorpUserInfoResponse> userListResponses = new ArrayList<>(corpUserInfos.size());
        for (CorpUserInfo corpUserInfo : corpUserInfos) {
            CorpUserInfoResponse userInfoResponse = new CorpUserInfoResponse();
            userInfoResponse.setId(corpUserInfo.getId());
            userInfoResponse.setCorpId(corpUserInfo.getCorpId());
            userInfoResponse.setUserId(corpUserInfo.getUserId());
            userInfoResponse.setUsername(corpUserInfo.getUsername());
            userInfoResponse.setAvatar(corpUserInfo.getAvatar());
            userInfoResponse.setCreateTime(corpUserInfo.getCreateTime());
            userInfoResponse.setHasDeleted(corpUserInfo.getHasDeleted());
            userInfoResponse.setHasAdmin(corpUserInfo.getHasAdmin());
            userInfoResponse.setHasSuperAdmin(corpUserInfo.getHasSuperAdmin());
            userInfoResponse.setRegisterChannel(corpUserInfo.getRegisterChannel());
            String departmentNames = Optional.ofNullable(corpUserInfo.getDepartments())
                    .map(it -> Arrays.stream(it.split(",")).filter(StringUtils::isNotBlank).map(Long::parseLong).map(departmentMap::get).collect(Collectors.toList()))
                    .map(it -> String.join(",", it))
                    .orElse(null);
            userInfoResponse.setDepartments(departmentNames);
            String departmentName = Optional.ofNullable(corpUserInfo.getDefaultDepartment())
                    .map(Integer::longValue)
                    .map(departmentMap::get)
                    .orElse("");
            userInfoResponse.setDefaultDepartment(departmentName);
            userListResponses.add(userInfoResponse);
        }

        return PageConvertor.convertPage(pageInfo, userListResponses);
    }

    @NotNull
    private Map<Long, String> getDepartmentMap(List<CorpUserInfo> corpUserInfos) {
        Set<String> departmentIds = corpUserInfos.stream().flatMap(it -> Arrays.stream(it.getDepartments().split(",")).filter(StringUtils::isNotBlank)).collect(Collectors.toSet());
        Map<Long, String> departmentMap = Collections.emptyMap();
        if (CollectionUtils.isNotEmpty(departmentIds)) {
            QueryWrapper<CorpDepartmentInfo> departmentQuery = new QueryWrapper<>();
            departmentQuery.lambda().in(CorpDepartmentInfo::getId, departmentIds);
            List<CorpDepartmentInfo> departmentInfos = corpDepartmentInfoService.list(departmentQuery);
            departmentMap = departmentInfos.stream().collect(Collectors.toMap(CorpDepartmentInfo::getId, CorpDepartmentInfo::getDepartmentName, (a, b) -> a));
        }
        return departmentMap;
    }

    @Override
    public void editUserPassword(EditUserPasswordRequest editUserPasswordRequest) {
        QueryWrapper<CorpUserInfo> userQuery = new QueryWrapper<>();
        userQuery.lambda().eq(CorpUserInfo::getId, editUserPasswordRequest.getId());
        CorpUserInfo corpUserInfo = corpUserInfoService.getOne(userQuery);
        if (Objects.isNull(corpUserInfo)) {
            throw new ParameterException("获取用户信息失败");
        }
        QueryWrapper<Account> accountQuery = new QueryWrapper<>();
        accountQuery.lambda().eq(Account::getUserId, corpUserInfo.getUserId());
        Account account = getOne(accountQuery);
        if (Objects.isNull(account)) {
            throw new ParameterException("获取用户账户信息失败");
        }
        Account updateAccount = new Account();
        updateAccount.setId(account.getId());
        updateAccount.setPassword(MD5Utils.md5(SLOT_AITREASURECHEST_KEY + editUserPasswordRequest.getPassword()));
        updateById(updateAccount);
    }

    @NotNull
    private Account loginVerifyByPassword(String phoneNumber, String password) {
        String md5Key = SLOT_AITREASURECHEST_KEY + password;
        QueryWrapper<Account> accountQuery = new QueryWrapper<>();
        accountQuery.lambda().eq(Account::getPhoneNumber, phoneNumber)
                .eq(Account::getPassword, MD5Utils.md5(md5Key));
        Account account = this.getOne(accountQuery);
        if (Objects.isNull(account)) {
            throw new ServiceException("账号或密码错误");
        }
        return account;
    }

    @NotNull
    private CorpInfo getAndVerifyCorpInfo(CorpInvitationCode corpInvitationCode) {
        QueryWrapper<CorpInfo> corpInfoQueryWrapper = new QueryWrapper<>();
        corpInfoQueryWrapper.lambda()
                .eq(CorpInfo::getInviteCode, corpInvitationCode.getValue())
        ;
        CorpInfo corpInfo = corpInfoService.getOne(corpInfoQueryWrapper);
        if (Objects.isNull(corpInfo)) {
            throw new ServiceException("认证码无效，请从指定入口跳转登录");
        }
        if (corpInfo.getExpiryDate().isBefore(LocalDate.now())) {
            throw new ServiceException("企业已到期，corpId=" + corpInfo.getCorpId());
        }
        return corpInfo;
    }

    /**
     * 验证码校验，并自动创建新账户
     *
     * @param loginRequest
     * @param corpInfo
     * @param now
     * @param loginRouteEnum
     * @return
     */
    private Account loginVerifyByVerifyCode(LoginRequest loginRequest, CorpInfo corpInfo, LocalDateTime now, LoginRouteEnum loginRouteEnum) {
        // 验证码校验
        this.codeVerified(loginRequest.getPhoneNumber(), loginRequest.getPassword());
        QueryWrapper<Account> accountQueryWrapper = new QueryWrapper<>();
        accountQueryWrapper.eq("phone_number", loginRequest.getPhoneNumber());
        Account account = this.getOne(accountQueryWrapper);
        if (Objects.isNull(account)) {
            if (!Objects.equals(loginRouteEnum, LoginRouteEnum.NORMAL_LOGIN_ROUTE)) {
                throw new ServiceException("该管理员账户不存在，请先配置管理员账户后再次尝试登录");
            }
            // 自动为其创建账户以及企业用户信息
            return createAccountAndCorpUserInfo(RandomIdGenerator.userId(corpInfo.getCorpId()), loginRequest.getPhoneNumber(), corpInfo, now, RegisterChannelEnum.SYSTEM_REGIS, false, null);
        }
        return account;
    }

    /**
     * 创建account及corp_user_info
     *
     * @param userId
     * @param phoneNumber
     * @param corpInfo
     * @param now
     * @param registerChannelEnum
     * @param hasCorpAdmin
     * @param password
     * @return
     */
    @NotNull
    private Account createAccountAndCorpUserInfo(String userId, String phoneNumber, CorpInfo corpInfo, LocalDateTime now, RegisterChannelEnum registerChannelEnum, boolean hasCorpAdmin, String password) {
        // 创建新账户
        Account createAccount = getCreateAccount(userId, phoneNumber, password, now);
        this.save(createAccount);
        // 插入corpUserInfo 记录
        insertCorpUserInfo(corpInfo, createAccount, now, registerChannelEnum, hasCorpAdmin);
        return createAccount;
    }

    /**
     * 获取账户创建信息
     *
     * @param userId
     * @param phoneNumber
     * @param password
     * @param now
     * @return
     */
    @NotNull
    private static Account getCreateAccount(String userId, String phoneNumber, String password, LocalDateTime now) {
        Account createAccount = new Account();
        createAccount.setPhoneNumber(phoneNumber);
        if (StringUtils.isNotEmpty(password)) {
            createAccount.setPassword(MD5Utils.md5(SLOT_AITREASURECHEST_KEY + password));
        }
        createAccount.setLastLogin(now);
        createAccount.setUserId(userId);
        return createAccount;
    }

    /**
     * 验证码校验
     *
     * @param phoneNumber
     * @param password
     */
    private Account codeVerified(String phoneNumber, String password) {
        // 验证码校验
        SmsVerifyCodeInfo verifyInfo = smsService.getVerifyInfo(new PhoneNumber(phoneNumber), new VerifyCode(password));
        if (Objects.isNull(verifyInfo)) {
            throw new ServiceException("验证码不正确或已过期");
        }
        QueryWrapper<Account> accountQuery = new QueryWrapper<>();
        accountQuery.lambda().eq(Account::getPhoneNumber, phoneNumber);
        return getOne(accountQuery);
    }

    /**
     * 获取企业用户信息
     *
     * @param userId
     * @param loginRouteEnum 根据特定的登录入口，对用户的身份标识加限制
     * @return
     */
    private List<CorpUserInfo> getCorpUserInfoList(String userId, LoginRouteEnum loginRouteEnum) {
        QueryWrapper<CorpUserInfo> corpUserInfoQuery = new QueryWrapper<>();
        corpUserInfoQuery.lambda().eq(CorpUserInfo::getUserId, userId);
        return corpUserInfoService.list(corpUserInfoQuery);
    }


    /**
     * 新增企业人员
     *
     * @param corpInfo
     * @param createAccount
     * @param now
     * @param registerChannelEnum
     * @param hasCorpAdmin
     */
    private void insertCorpUserInfo(CorpInfo corpInfo, Account createAccount, LocalDateTime now, RegisterChannelEnum registerChannelEnum, boolean hasCorpAdmin) {
        this.checkCorpUserLimit(corpInfo);
        CorpUserInfo corpUserInfo = new CorpUserInfo();
        corpUserInfo.setCorpId(corpInfo.getCorpId());
        corpUserInfo.setUserId(createAccount.getUserId());
        corpUserInfo.setUsername("游客-" + createAccount.getUserId());
        corpUserInfo.setAvatar("default");
        corpUserInfo.setCreateTime(now);
        corpUserInfo.setHasDeleted(false);
        corpUserInfo.setHasAdmin(hasCorpAdmin);
        corpUserInfo.setHasDefault(true);
        corpUserInfo.setHasSuperAdmin(false);
        corpUserInfo.setRegisterChannel(registerChannelEnum.getCode());
        corpUserInfoService.save(corpUserInfo);
    }

    /**
     * 校验企业人数限制
     *
     * @param corpInfo
     */
    private void checkCorpUserLimit(CorpInfo corpInfo) {
        if (Objects.isNull(corpInfo)) {
            return;
        }
        Integer userLimit = corpInfo.getUserLimit();
        if (userLimit == -1) {
            return;
        }
        QueryWrapper<CorpUserInfo> userQuery = new QueryWrapper<>();
        userQuery.lambda().eq(CorpUserInfo::getCorpId, corpInfo.getCorpId())
                .eq(CorpUserInfo::getHasDeleted, Boolean.FALSE);
        long corpUserCount = corpUserInfoService.count(userQuery);
        if (userLimit.longValue() < corpUserCount + 1) {
            throw new ServiceException("企业/高校已达最大限制注册人数（" + userLimit + "），请联系供应商进行调整");
        }
    }
}
